package cn.yx.common.core.service;

import cn.yx.common.core.pojo.PageDto;
import cn.yx.common.core.pojo.singletable.SingleCond;
import cn.yx.common.core.pojo.singletable.SingleDto;

import java.io.Serializable;
import java.util.List;

/**
 * <p>BaseService接口，定义了常用的Service方法，完成CRUD操作</p>
 *
 * @param <Dto>  DTO类
 * @param <Cond> Cond类
 * @param <Id>   ID主键值类
 * @author Wgssmart
 */
public interface BaseService<Dto extends SingleDto,
        Cond extends SingleCond,
        Id extends Serializable> {

    /**
     * 保存单条数据
     *
     * @param dto 需要保存的数据
     * @return 是否保存成功
     */
    boolean save(Dto dto);

    /**
     * 批量保存数据
     *
     * @param dtoList 需要批量保存的数据列表
     * @return 如果插入数据的条数与当前dtoList的size一致，则返回真，表示完全插入，否则表示有部分数据未插入成功
     */
    boolean save(List<Dto> dtoList);

    /**
     * 批量保存数据
     *
     * @param dtoList   需要批量保存的数据列表
     * @param batchSize 批量提交的条数
     * @return 是否保存成功
     */
    boolean save(List<Dto> dtoList, int batchSize);

    /**
     * 根据主键判断数据是否存在，如果不存在则插入，存在则更新
     *
     * @param dto 需要更新或保存的数据
     * @return 是否保存或更新成功
     */
    boolean saveOrUpdate(Dto dto);

    /**
     * 根据updateCond来判断是否更新数据，规则：
     * 如果满足updateCond条件，则更新数据（可能有多条满足条件的数据被更新成指定的DTO数据），否则插入DTO对应的一条记录。
     *
     * @param dto        如果是更新数据，则更新为DTO指定的数据，否则插入DTO数据
     * @param updateCond 按此条件来更新数据，如果不符合此条件条件，则执行saveOrUpdate(DTO dto)方法
     * @return 是否保存或更新成功
     */
    boolean saveOrUpdate(Dto dto, Cond updateCond);

    /**
     * 批量保存或更新数据，根据主键判断数据是否存在
     *
     * @param dtoList 需要批量保存或更新的数据列表
     * @return 如果插入数据的条数加上更新数据的条数与当前dtoList的size一致，则返回真，表示完全保存或插入，否则表示有部分数据未保存或插入成功
     */
    boolean saveOrUpdate(List<Dto> dtoList);

    /**
     * 批量保存或更新，根据主键判断数据是否存在
     *
     * @param dtoList   需要批量保存或更新的数据列表
     * @param batchSize 批量提交的条数
     * @return 是否保存或更新成功
     */
    boolean saveOrUpdate(List<Dto> dtoList, int batchSize);

    /**
     * 根据主键删除单条数据
     *
     * @param id 主键值
     * @return 是否删除成功
     */
    boolean remove(Id id);

    /**
     * 根据多个主键批量删除多条数据
     *
     * @param idList 主键值列表
     * @return 如果删除数据的条数与当前idList的size一致，则返回真，表示完全删除，否则表示有部分数据未删除成功或部分数据本身不存在于数据库中
     */
    boolean remove(List<Id> idList);

    /**
     * 根据条件删除数据
     *
     * @param deleteCond 删除数据的条件
     * @return 是否删除成功
     */
    boolean remove(Cond deleteCond);

    /**
     * 根据主键id更新数据，属性为null的，更新时会被忽略（字段不会被更新为null）
     *
     * @param dto 需要更新的数据对象，必须包含主键值
     * @return 是否更新成功
     */
    boolean update(Dto dto);

    /**
     * 根据主键id批量更新数据，属性为null的，更新时会被忽略（字段不会被更新为null）
     *
     * @param dtoList 需要批量更新的数据对象，必须包含主键值
     * @return 如果更新数据的条数与当前dtoList的size一致，则返回真，表示完全更新，否则表示有部分数据未更新成功或部分数据本身不存在于数据库中
     */
    boolean update(List<Dto> dtoList);

    /**
     * 根据主键id批量更新数据，属性为null的，更新时会被忽略（字段不会被更新为null）
     *
     * @param dtoList   需要批量更新的数据对象，必须包含主键值
     * @param batchSize 批量提交的条数
     * @return 是否更新成功
     */
    boolean update(List<Dto> dtoList, int batchSize);

    /**
     * 根据条件更新数据（可能更新多条满足条件的数据），dto中指定的属性为null时，字段不会被更新为null
     *
     * @param dto        把数据更新成DTO中指定的数据
     * @param updateCond 更新数据的条件，按照此条件来更新数据
     * @return 是否更新成功
     */
    boolean update(Dto dto, Cond updateCond);

    /**
     * 更新数据，如果DTO中的属性为null，则字段更新为null
     *
     * @param dto 把数据更新成DTO中指定的数据，如果属性为null，字段也更新为null
     * @return 是否更新所有字段成功
     */
    boolean updateAllColumn(Dto dto);

    /**
     * 批量更新数据，如果DTO中的属性为null，则字段更新为null
     *
     * @param dtoList 把数据更新成DTO中指定的数据，如果属性为null，字段也更新为null
     * @return 如果更新数据的条数与当前dtoList的size一致，则返回真，表示完全更新，否则表示有部分数据未更新成功或部分数据本身不存在于数据库中
     */
    boolean updateAllColumn(List<Dto> dtoList);

    /**
     * 批量更新数据，如果DTO中的属性为null，则字段更新为null
     *
     * @param dtoList   把数据更新成DTO中指定的数据，如果属性为null，字段也更新为null
     * @param batchSize 批量提交的条数
     * @return 是否更新所有字段成功
     */
    boolean updateAllColumn(List<Dto> dtoList, int batchSize);

    /**
     * 根据条件更新数据，如果DTO中的属性为null，则字段更新为null
     *
     * @param dto        把数据更新成DTO中指定的数据，如果属性为null，字段也更新为null
     * @param updateCond 更新数据的条件，按照此条件来更新数据
     * @return 是否更新所有字段成功
     */
    boolean updateAllColumn(Dto dto, Cond updateCond);

    /**
     * 根据主键查询单个数据
     *
     * @param id 主键值
     * @return 指定id的数据
     */
    Dto getOne(Id id);

    /**
     * 根据查询条件查询一条记录，如果结果集中包含多条记录会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")
     *
     * @param selectCond 查询条件
     * @return 符合条件的单条数据
     */
    Dto getOne(Cond selectCond);

    /**
     * 根据查询条件查询一条记录，可指定在多个数据的情况下是否抛出异常。
     * 如果指定不抛出异常，则获取满足条件的第一条数据，如果指定抛出异常，当有多条数据时，抛出异常。
     *
     * @param selectCond 查询条件
     * @param throwEx    如果返回结果为多条时，是否抛出异常
     * @return 符合条件的单条数据
     */
    Dto getOne(Cond selectCond, boolean throwEx);

    /**
     * 查询所有
     *
     * @return 所有数据
     */
    List<Dto> listAll();

    /**
     * 条件查询所有
     *
     * @param selectCond 查询条件
     * @return 条件查询条件的所有数据
     */
    List<Dto> listAll(Cond selectCond);

    /**
     * 根据多个主键id批量查询
     *
     * @param idList 主键值列表
     * @return 多个id对应的数据列表
     */
    List<Dto> listAll(List<Id> idList);

    /**
     * 条件分页查询
     *
     * @param selectCond 查询条件
     * @return 符合查询条件的分页数据
     */
    PageDto<Dto> page(Cond selectCond);

    /**
     * 查询总记录数
     *
     * @return 总记录数
     */
    long count();

    /**
     * 根据条件查询总记录数
     *
     * @param selectCond 查询条件
     * @return 符合查询条件的记录数
     */
    long count(Cond selectCond);

}
